package com.atguigu.bean;

import com.atguigu.annoation.Bean;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

public class AnnotationApplicationContext implements ApplicationContext{

//    创建map集合，放bean对象
    private static Map<Class,Object> beanFactory=new HashMap<>();
    private static String rootPath;
//    返回对象
    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

//    创建它的有参数构造，传递包的路径，设置包扫描规则
//    当前包及其子包，哪个类有@Bean注解，就把这个类通过反射实例化
//    public AnnotationApplicationContext(String basePackage) {
    public static void pathDemo1(String basePackage) {

        try {
            //        1.把点替换成\
            String packagePath = basePackage.replaceAll("\\.", "\\\\");
            //        2.获取包的绝对路径
            Enumeration<URL> urls = Thread.currentThread().getContextClassLoader().getResources(packagePath);
            while (urls.hasMoreElements()){
                URL url = urls.nextElement();
                String filePath = URLDecoder.decode(url.getFile(), "utf-8");
//                获取包前面的路径部分，进行字符串截取
                rootPath = filePath.substring(0,filePath.length()-packagePath.length());
//                包扫描
                loadBean(new File(filePath));

            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

//    包扫描的过程，实例化
    private static void loadBean(File file) throws Exception {
//        1.做个判断，当前内容是否是文件夹
        if(file.isDirectory()){

//        2.获取文件夹中内容
            File[] childrenFiles = file.listFiles();
//        3.判断文件夹是否为空，直接返回
            if (childrenFiles==null || childrenFiles.length==0)
                return;
//        4.如果不为空，遍历文件夹中所有内容
            for (File childFile : childrenFiles){
    //        4.1遍历得到每个file对象，继续判断，如果还是文件夹，则递归判断。
                if (childFile.isDirectory()){
                    loadBean(childFile);
                }else {
                    //        4.2如果为文件
                    //        4.3得到包路径+类名称部分-字符串截取
                    String pathWithClasses = childFile.getAbsolutePath().substring(rootPath.length() - 1);
                    //        4.4当前文件的类型是否为class类型
                    if (pathWithClasses.contains(".class")){
                        //        4.5如果是class类型，把路径\替换成. 把.class去掉
                        String allName = pathWithClasses.replaceAll("\\\\", ".").replace(".class", "");
                        //        4.6判断类上是否有@bean注解，如果有通过反射实例化对象
//                        4.6.1获取类的class
                        Class clazz = Class.forName(allName);
//                        4.6.2判断不是接口
                        if (!clazz.isInterface()){
//                            4.6.3是否有注解
                            Bean annotation = (Bean) clazz.getAnnotation(Bean.class);
                            if (annotation!=null){
//                            4.6.4实例化
                                Object instance = clazz.getConstructor().newInstance();
                    //        4.7把对象实例化之后，放到map集合beanFactory中
//                                4.7.1判断当前类有接口，就让这个为他们的key
                                if (clazz.getInterfaces().length>0){
                                    beanFactory.put(clazz.getInterfaces()[0],instance);
                                }else {
                                    beanFactory.put(clazz,instance);
                                }

                            }
                        }

                    }

                }
            }

        }

    }

    public static void main(String[] args) {
        pathDemo1("com.atguigu");
    }
//    public static void main(String[] args) {
//        ApplicationContext applicationContext = new AnnotationApplicationContext("com.atguigu");
//        applicationContext.getBean(User.class);
//
//    }
}
